/*

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at 
  
           http://www.mozilla.org/MPL/ 
  
  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License. 
  
  The Original Code is Indigo framework applicatif.
  
  The Initial Developer of the Original Code is
  Olivier Bugalotto (aka Iteratif) <olivier.bugalotto@iteratif.net>.
  Portions created by the Initial Developer are Copyright (C) 2004-2008
  the Initial Developer. All Rights Reserved.
  
  Contributor(s) :
  
*/
package indigo.collections
{
	import flash.errors.IllegalOperationError;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	
	import indigo.ICloneable;

	/**
	 *
	 * Implementation de l'interface <code>IList</code>.<br>
	 * La classe <code>ArrayList</code> represente une collection non generique d'objets
	 * <br>dont les objets sont accessible a partir d'un index.
	 * 
	 * @example Voici un exemple qui manipule des chaines de caracteres:
	 * <listing version="3.0">
	 * var list:ArrayList = new ArrayList(["France","Allemagne","Angleterre"]);
	 * trace(list[2]); // Angleterre
	 * 
	 * if(list.contains("Allemagne")) {
	 * 		list.insert(list.indexOf("Allemagne"),"Suisse");
	 * }
	 * 
	 * trace(list); // France,Suisse,Allemagne,Angleterre
	 * </listing>
	 * 
	 *
	 * @see IList
	 */
	public class ArrayList extends Proxy implements IList, ICloneable
	{
		private var _items:Array;
		
		/**
		 * Creer un nouvel objet <code>ArrayList</code>
		 * @param source	Reference d'un tableau permettant d'initialiser un objet <code>ArrayList</code>
		 * 
		 */
		public function ArrayList(source:Array = null)
		{
			super();
			if(source)
				_items = source;
			else
				_items = [];
		}
		
		/**
		 * Obtenir un element depuis son index dans <code>ArrayList</code>
		 * a l'aide de la syntaxe [].
		 * 
		 * @param name
		 * @return 
		 * 
		 */
		flash_proxy override function getProperty(name:*):* {
			return getItemAt(name);
		}
		
		/**
		 * Definit un element depuis un index specifie dans <code>ArrayList</code>
		 * @param name
		 * @param value
		 * 
		 */
		flash_proxy override function setProperty(name:*, value:*):void {
			insert(name,value);
		}
		
		// Permet de parcourir les éléments internes à l'aide d'une boucle for..in ou for each..in
		override flash_proxy function nextNameIndex (index:int):int {	     
	         if (index < _items.length) {
	             return index + 1;
	         } else {
	             return 0;
	         }
	     }
	     
	     override flash_proxy function nextName(index:int):String {
	         return _items[index - 1];
	     }
	     
	     flash_proxy override function nextValue(index:int):* {
	     	return _items[index - 1];
	     }
		
		/**
		 * 
		 * @return 
		 * @inheritDoc
		 */
		public function getEnumerator():IEnumerator
		{
			return new Enumerator(_items);
		}
		
		/**
		 * 
		 * @return 
		 * @inheritDoc
		 */
		public function get count():uint
		{
			return _items.length;
		}
		
		/**
		 * 
		 * @param item
		 * @inheritDoc
		 */
		public function add(item:Object):uint
		{
			return _items.push(item);
		}
		
		/**
		 * 
		 * @return 
		 * @inheritDoc
		 */
		public function arrayTo(index:int = 0):Array
		{
			return _items.slice(index);
		}
		
		/**
		 * 
		 *@inheritDoc 
		 */
		public function clear():void
		{
			_items = [];
		}
		
		/**
		 * 
		 * @param item
		 * @return 
		 * @inheritDoc
		 */
		public function contains(item:Object):Boolean
		{
			var e:IEnumerator = getEnumerator();
			while(e.moveNext()) {
				if(e.current == item)
					return true;
			}
			return false;
		}
		
		/**
		 * 
		 * @param item
		 * @return 
		 * @inheritDoc
		 */
		public function indexOf(item:Object):int
		{
			return _items.indexOf(item);
		}
		
		/**
		 * 
		 * @param index
		 * @param item
		 * @inheritDoc
		 */
		public function insert(index:int, item:Object):void
		{
			if(index < 0 || index > _items.length) throw new IllegalOperationError();
			
			_items[index] = item;
		}
		
		/**
		 * 
		 * @param item
		 * @inheritDoc
		 */
		public function remove(item:Object):Object
		{
			var index:int = indexOf(item);
			return _items.splice(index,1)[0];
		}
		
		/**
		 * 
		 * @param index
		 * @inheritDoc
		 */
		public function removeAt(index:int):Object {
			var item:Object = getItemAt(index);
			return remove(item);
		}

		/**
		 * 
		 * @param index
		 * @return 
		 * @inheritDoc
		 */
		public function getItemAt(index:int):Object
		{
			if(index < 0 || index > _items.length) throw new IllegalOperationError();
			
			return _items[index];
		}
		
		public function clone():Object {
			var list:ArrayList = new ArrayList(_items.slice());
			return list;
		}
		
		/**
		 * Affiche dans une chaine de caracteres les elements contenus dans <code>ArrayList</code>
		 * @return 
		 * 
		 */
		public function toString():String {
			return _items.toString();
		}
		
	}
}